#pragma once

#include <pthread.h>
#include <semaphore.h>
#include "Noncopyable.h"

namespace utils
{

class Mutex : Noncopyable
{
public:
    Mutex();
    ~Mutex();
    void lock();
    void unlock();

private:
    pthread_mutex_t mutex_;
};

class RWMutex : Noncopyable
{
public:
    RWMutex();
    ~RWMutex();
    void rdlock(); 
    void wrlock();
    void unlock();

private:
    pthread_rwlock_t mutex_;
};

class SpinMutex : Noncopyable
{
public:
    SpinMutex();
    ~SpinMutex();
    void lock();
    void unlock();

private:
    pthread_spinlock_t mutex_;
};

template<typename TMutex>
class LockGuard
{
public:
    LockGuard(TMutex& mutex)
        : mutex_(mutex)
    {
        lock();
    }

    ~LockGuard()
    {
        unlock();
    }

    void lock()
    {
        mutex_.lock();
    }

    void unlock()
    {
        mutex_.unlock();
    }

private:
    TMutex& mutex_;
};

class ReadLock 
{
public:
    ReadLock(RWMutex& mutex);
    ~ReadLock();
    void lock();
    void unlock();

private:
    RWMutex& mutex_;
};
 
class WriteLock 
{
public:
    WriteLock(RWMutex& mutex);
    ~WriteLock();
    void lock();
    void unlock();

private:
    RWMutex& mutex_;
};

class Semaphore
{
public:
    Semaphore(unsigned int value = 1);
    ~Semaphore();
    void wait();
    void notify();

private:
    sem_t m_sem;
};

} // namespace utils
